package tables

import (
	"fmt"
	"log"
	"net"
	"ospf/common"
	"time"

	"github.com/spf13/viper"
	"github.com/vishvananda/netlink"
)

type OspfLSDB struct {
	RouterID   common.ID
	NeighT     *NeighborTable
	LinkStateT *LinkStateTable
	RoutingT   *RoutingTable
}

func NewOspfLSDB(id common.ID) *OspfLSDB {
	lsDB := &OspfLSDB{
		RouterID: id,
		NeighT: &NeighborTable{
			t: make(map[common.ID]*Neighbor),
		},
		LinkStateT: &LinkStateTable{
			Nodes: make(map[common.ID]*Node),
			Edges: make(map[common.ID][]Edge),
		},
		RoutingT: &RoutingTable{
			Routes: make(map[common.ID]Route),
		},
	}
	routes, err := netlink.RouteList(nil, netlink.FAMILY_V4)
	if err != nil {
		log.Fatal(err)
	}
	for _, route := range routes {

		err = lsDB.RoutingT.AddRouteTable(
			common.ParseCIDR(route.Dst.String()),
			Route{
				NextHop: common.ParseIP(route.Gw.String()),
				Cost:    10,
			},
		)
		if err != nil {
			log.Println(common.ErrUpdateRouting("initialize routing table failed." + err.Error()))
			return nil
		}
	}
	return lsDB
}

// PruneProcess 开启定期清理表所有数据表的过期表项
func (o *OspfLSDB) PruneProcess() {
	for {
		o.NeighT.Prune()
		time.Sleep(1 * time.Second)
	}
}

func GenTestOspfLSDB() *OspfLSDB {
	viper.AddConfigPath("../conf")
	viper.SetConfigName("conf")
	viper.SetConfigType("json")

	if err := viper.ReadInConfig(); err != nil {
		fmt.Printf("Error reading config file, %s", err)
	}

	local := viper.Get("local").([]map[string]interface{})
	id := common.ID(net.ParseIP(local[0]["ip"].(string)).To4())
	lsDB := NewOspfLSDB(id)
	return lsDB
}
